import { OnInit, Component, EventEmitter, Injector, Output, ViewChild, OnChanges, Input, SimpleChanges } from '@angular/core';
import { AppComponentBase } from '@shared/common/app-component-base';
import { EntityDtoOfGuid, MoveItemInput, SetTaxonomyItemStatusInput, TaxonomyItemDataOut, TaxonomyServiceProxy } from '@shared/service-proxies/service-proxies';
import { filter as _filter, remove as _remove } from 'lodash-es';
import { throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';

import { TreeNode, MenuItem } from 'primeng/api';

import { ArrayToTreeConverterService } from '@shared/utils/service/array-to-tree-converter.service';
import { TreeDataHelperService } from '@shared/utils/service/tree-data-helper.service';


@Component({
    selector: 'taxonomy-tree',
    templateUrl: './taxonomy-tree.component.html'
})
export class TaxonomyTreeComponent extends AppComponentBase implements OnInit,OnChanges {

    @Output() addTaxonomyItem = new EventEmitter<any>();
    @Output() editTaxonomyItem = new EventEmitter<TaxonomyItemDataOut>();

    treeData: any;
    selectedOu: TreeNode;
    ouContextMenuItems: MenuItem[];
    canMoveItem = false;
    saving = false;

    @Input() typeId :string = null;

    private fieldMappings = [
        {
            target: 'label',
            targetFunction(item) {
                return item.displayName;
            }
        }, {
            target: 'expandedIcon',
            targetFunction(item) {
                if (item.isActive) {
                    return 'fa fa-folder-open text-warning';
                } else {
                    return 'fa fa-folder-open font-grey';
                }
            }
        },
        {
            target: 'collapsedIcon',
            targetFunction(item) {
                if (item.isActive) {
                    return 'fa fa-folder text-warning';
                } else {
                    return 'fa fa-folder font-grey';
                }
            }
        },
        {
            target: 'selectable',
            value: true
        }
    ];

    constructor(
        injector: Injector,
        private _taxonomyService: TaxonomyServiceProxy,
        private _arrayToTreeConverterService: ArrayToTreeConverterService,
        private _treeDataHelperService: TreeDataHelperService
    ) {
        super(injector);

        this.canMoveItem = this.isGranted('Pages_Manage_Taxonomy_Update');
        this.ouContextMenuItems = this.getContextItems();
    }

    totalUnitCount = 0;

    ngOnInit(): void {

    }

    ngOnChanges(changes: SimpleChanges): void {
        if (changes['typeId']) {
            if (this.typeId) {
                this.getTreeDataFromServer();
            }
        }
    }

    nodeSelect(event) {
        let item = <TaxonomyItemDataOut>this.selectedOu.data;
        this.editTaxonomyItem.emit(item);
    }

    isDroppingBetweenTwoNodes(event: any): boolean {
        return event.originalEvent.target.nodeName === 'LI';
    }

    nodeDrop(event) {
        const input = new MoveItemInput();
        input.id = event.dragNode.data.id;
        let dropNodeDisplayName = '';

        if (this.isDroppingBetweenTwoNodes(event)) {//between two item
            input.parentId = event.dropNode.parent ? event.dropNode.parent.data.id : null;
            dropNodeDisplayName = event.dropNode.parent ? event.dropNode.parent.data.displayName : this.l('Root');
        } else {
            input.parentId = event.dropNode.data.id;
            dropNodeDisplayName = event.dropNode.data.displayName;
        }

        this.message.confirm(
            this.l('OrganizationUnitMoveConfirmMessage', event.dragNode.data.displayName, dropNodeDisplayName),
            this.l('AreYouSure'),
            isConfirmed => {
                if (isConfirmed) {
                    this._taxonomyService.moveTaxonomyItem(input)
                        .pipe(catchError(error => {
                            this.revertDragDrop();
                            return throwError(error);
                        }))
                        .subscribe(() => {
                            this.notify.success(this.l('SuccessfullyMoved'));
                            this.reload();
                        });
                } else {
                    this.revertDragDrop();
                }
            }
        );
    }


    reload(): void {
        this.getTreeDataFromServer();
    }

    private revertDragDrop() {
        this.reload();
    }

    private getTreeDataFromServer(): void {
        this._taxonomyService.getTaxonomyItemTree(this.typeId)
        .subscribe((result: TaxonomyItemDataOut[]) => {
            this.totalUnitCount = result.length;
            this.treeData = this._arrayToTreeConverterService.createTree(result,
                'parentId',
                'id',
                null,
                'children',
                this.fieldMappings,
                (a, b) => a.norder - b.norder
                );
            this.addTaxonomyItem.emit(null);
        });
    }

    private getContextItems(): any[] {
        const permissions = {
            create: this.isGranted('Pages_Manage_Taxonomy_Create'),
            edit: this.isGranted('Pages_Manage_Taxonomy_Update'),
            delete: this.isGranted('Pages_Manage_Taxonomy_Delete')
        };

        let items = [
            {
                label: this.l('AddSubDataItem'),
                disabled: !permissions.create,
                command: () => {
                    let item = <TaxonomyItemDataOut>this.selectedOu.data;
                    this.addTaxonomyItem.emit({item : item , typeId: this.typeId});
                }
            },
            {
                label: this.l('Delete'),
                disabled: !permissions.delete,
                command: () => {
                    this.message.confirm(
                        this.l('DeleteWarningMessage', this.selectedOu.data.displayName),
                        this.l('AreYouSure'),
                        isConfirmed => {
                            if (isConfirmed) {
                                this._taxonomyService.deleteTaxonomyItem([this.selectedOu.data.id])
                                .subscribe(() => {
                                    this.deleteTaxonomyItem(this.selectedOu.data.id);
                                    this.notify.success(this.l('SuccessfullyDeleted'));
                                    this.selectedOu = null;
                                    this.addTaxonomyItem.emit(null);
                                });
                            }
                        }
                    );
                }
            },
            {
                label: this.l('Release'),
                disabled: !permissions.edit,
                command: () => {
                    const input = new SetTaxonomyItemStatusInput({
                        id: this.selectedOu.data.id,
                        isActive : true
                    })
                    this._taxonomyService.setTaxonomyItemStatus(input)
                    .subscribe(result => {
                        this.taxonomyItemUpdated(result);
                        this.notify.success(this.l('ReleaseSuccessfully'));
                    });
                }
            },
            {
                label: this.l('CancelRelease'),
                disabled: !permissions.edit,
                command: () => {
                    const input = new SetTaxonomyItemStatusInput({
                        id: this.selectedOu.data.id,
                        isActive : false
                    })
                    this._taxonomyService.setTaxonomyItemStatus(input)
                    .subscribe(result => {
                        this.taxonomyItemUpdated(result);
                        this.notify.success(this.l('CancelReleaseSuccessfully'));
                    });
                }
            },
            {
                label: this.l('UpSort'),
                disabled: !permissions.edit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._taxonomyService.upTaxonomyItemSort(input)
                    .subscribe(result => {
                        result.items.forEach(t => {
                            this.taxonomyItemUpdated(t);
                        });

                        this.notify.success(this.l('OrderSuccessSuccessfully'));
                    });
                }
            },
            {
                label: this.l('DownSort'),
                disabled: !permissions.edit,
                command: () => {
                    const input = new EntityDtoOfGuid({
                        id: this.selectedOu.data.id
                    })
                    this._taxonomyService.downTaxonomyItemSort(input)
                    .subscribe((result) => {
                        result.items.forEach(t => {
                            this.taxonomyItemUpdated(t);
                        });
                        this.notify.success(this.l('OrderSuccessSuccessfully'));
                    });
                }
            }
        ];


        return items;
    }

    taxonomyItemCreated(ou: TaxonomyItemDataOut): void {
        let newNode = {
            data: ou,
            children: [],
            selected: true
        };

        this._arrayToTreeConverterService.mapFields(ou, newNode, this.fieldMappings);

        if (ou.parentId) {
            let unit = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.parentId } });
            if (!unit) {
                return;
            }

            unit.children.push(newNode);

            if (unit.expanded !== true) {
                unit.expanded = true;
            }
        } else {
            this.treeData.push(newNode);
        }

        this.totalUnitCount += 1;
    }

    private deleteTaxonomyItem(id) {
        let node = this._treeDataHelperService.findNode(this.treeData, { data: { id: id } });
        if (!node) {
            return;
        }

        if (!node.data.parentId) {
            _remove(this.treeData, {
                data: {
                    id: id
                }
            });
        }

        let parentNode = this._treeDataHelperService.findNode(this.treeData, { data: { id: node.data.parentId } });
        if (!parentNode) {
            return;
        }

        _remove(parentNode.children, {
            data: {
                id: id
            }
        });

        this.totalUnitCount -= 1;
    }

    taxonomyItemUpdated(ou: TaxonomyItemDataOut): void {
        let item = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.id } });
        if (!item) {
            return;
        }
        this._arrayToTreeConverterService.mapFields(ou, item, this.fieldMappings);
        item.data = ou;

        if (ou.parentId) {
            let parentitem = this._treeDataHelperService.findNode(this.treeData, { data: { id: ou.parentId } });
            if (!parentitem) {
                return;
            }
            parentitem.children = parentitem.children.sort((a, b) => a.data.norder - b.data.norder);
        }else{
            this.treeData = this.treeData.sort((a, b) => a.data.norder - b.data.norder);
        }
    }

    addRootMenu(): void {
        this.addTaxonomyItem.emit({item : null , typeId: this.typeId});
    }

    expandAll() {
        this._treeDataHelperService.operateTreeNode(this.treeData, (t)=>t.expanded = true);
    }

    collapseAll() {
        this._treeDataHelperService.operateTreeNode(this.treeData, (t)=>t.expanded = false);
    }
}
